iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0

Day 6 拿 List 當 Queue,最後列了三個缺點:沒有 ACK、沒有重試、沒有消費者群組。今天的 Stream 三個都有,一個一個來看。

常用指令

Stream 是一份只會往後長的訊息紀錄,每一筆有自己的 ID,後面跟著任意多組 field-value。

  • XADD key * field value ...(加一筆,* 是讓 Redis 自己產 ID,回傳的就是那筆的 ID)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209mumTDJSDKV.png

  • XLEN key(有幾筆)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209VmQqc9JFbw.png

  • XRANGE key - +(撈一段出來,- 到 + 就是全部)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209KXeTIrM7tG.png

  • XGROUP CREATE key group 0(建消費者群組,0 是從第一筆開始發)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209nuaUehXCYv.png

  • XREADGROUP GROUP group consumer COUNT n STREAMS key >(用某個消費者的身分讀,> 是「還沒發給任何人的」)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209lzZgc3KDIH.png

  • XACK key group id ...(回報處理完了,回傳成功幾筆)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209qgBt5GRbzd.png

  • XPENDING key group(誰借走了還沒還)| 先建一個消費者 worker-2 拿走一條消息
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209mdaoNNWBJJ.png

  • XAUTOCLAIM key group consumer min-idle-time 0(把借太久沒還的搶過來)
    https://ithelp.ithome.com.tw/upload/images/20260922/20184209znM7oaazwh.png

訂單事件流

下單就往 stream 丟一筆,誰要用誰自己來讀:

XADD order:stream * orderId 1 amount 100
XADD order:stream * orderId 2 amount 250
XADD order:stream * orderId 3 amount 80

XLEN order:stream       # 3
XRANGE order:stream - +

https://ithelp.ithome.com.tw/upload/images/20260922/20184209R9ydBoZiDb.png

XADD 回傳的格式是「毫秒時間戳-序號」。同一毫秒進來好幾筆就往後加序號,所以不會重複,而且一定照時間排。

跟 List 最大的差別在這裡:RPOP 拿走就沒了,Stream 讀完資料還留在裡面。

消費者群組

訂單多的時候,同一支程式會開好幾份一起跑。但每一份都讀同一個 stream 的話,同一筆訂單就會被扣好幾次款。

放進同一個群組,Redis 就保證一筆只發給其中一個。g1 是群組名,c1、c2 是兩份程式:

XGROUP CREATE order:stream g1 0

XREADGROUP GROUP g1 c1 COUNT 2 STREAMS order:stream >   # c1 拿到前兩筆
XREADGROUP GROUP g1 c2 COUNT 2 STREAMS order:stream >   # c2 只拿到第三筆
XREADGROUP GROUP g1 c1 COUNT 2 STREAMS order:stream >   # 沒了,回 nil

https://ithelp.ithome.com.tw/upload/images/20260922/201842093JCESUjZjS.png

ACK

XREADGROUP 拿到只是「借走」,不算處理完:

XPENDING order:stream g1                              # 3 筆,c1 兩筆、c2 一筆

XACK order:stream g1 1790047274061-0 1790047277791-0  # c1 處理完了,回傳 2
XPENDING order:stream g1                              # 剩 1 筆,c2 那筆還掛著

沒 XACK 之前,這筆會一直掛在 pending 清單上。List 拿出去就消失了,機器處理到一半掛掉,沒人知道那筆訂單存在過;Stream 記得「這筆被誰借走、借多久了」。

XACK 只是把訊息從 pending 清單拿掉,不會刪資料。 三筆全部 ACK 完,XLEN 還是 3。

撿回來

XPENDING 加上範圍參數就看得到細節:

XPENDING order:stream g1 - + 10   # 1790047280883-0   c2   228660   1

https://ithelp.ithome.com.tw/upload/images/20260922/20184209oDeEmmzCtR.png

四個欄位是:訊息 ID、被誰借走、借了幾毫秒沒還、總共被發過幾次。

c2 掛掉了,那筆訂單就卡在這。XAUTOCLAIM 把借太久的搶過來給別人做:

XAUTOCLAIM order:stream g1 c1 10000 0   # 門檻 10 秒

XPENDING order:stream g1 - + 10         # 1790047280883-0   c1   5723   2

https://ithelp.ithome.com.tw/upload/images/20260922/20184209bVCgHF6MIf.png

10000 是「借超過幾毫秒才能搶」,最後那個 0 是從哪個 ID 開始掃。搶成功之後借的人從 c2 變成 c1,被發過的次數從 1 變 2,這就是重試。

次數這個欄位要記得看。同一筆一直被搶來搶去,代表它根本處理不了(髒資料、外部服務掛了),次數太多就該挑出來人工處理,不然它會永遠在群組裡繞。

踩雷

Stream 不會自己清。 ACK 不刪資料,讀過也不刪,就一路往後長。要限制長度得自己在 XADD 帶 MAXLEN:

XADD order:stream MAXLEN ~ 10 * orderId 1 amount 100

但 ~ 有陷阱。連續 XADD 300 筆、每筆都帶 MAXLEN ~ 10,最後量出來是 100 筆,不是 10(這行在主機的終端機下,不是在 redis-cli 裡面):

for i in $(seq 1 300); do docker exec redis30days redis-cli XADD trim:demo MAXLEN '~' 10 '*' n $i > /dev/null; done
XLEN trim:demo   # 100

https://ithelp.ithome.com.tw/upload/images/20260922/20184209E8f8uvB2z1.png

~ 的意思是「至少留 10 筆」,Redis 刪的時候是整個節點整個節點刪(stream-node-max-entries 預設 100),刪起來不划算就不刪。要精確就拿掉 ~ 寫 MAXLEN 10,同樣塞 300 筆就真的只剩 10 筆,代價是每次 XADD 都得真的去砍一次。

Spring Data Redis 3.4.1 沒有包 XAUTOCLAIM,只有 XCLAIM。Java 這邊得先 XPENDING 撈出來、自己比 idle 時間,再把超時的幾筆 XCLAIM 過來,Day 7 的 SINTERCARD、Day 9 的 BITCOUNT 也是一樣。

另外 Stream 有 ACK、有重試、有消費者群組,但沒有死信佇列、沒有路由、沒有延遲投遞。 跟 Day 6 的結論一樣,真的要當主要 MQ 還是得去用 RabbitMQ 或 Kafka。

今天內容比較多,Java 範例就先不列出來了~
Java 範例程式碼可以參考 https://github.com/gary880306/redis-30days/tree/dev

明天

七天都在講「哪個型別解決哪個問題」,但同樣存十個欄位,記憶體有時候省有時候不省,差在 Redis 偷偷換了底層結構。明天用 OBJECT ENCODING 看它什麼時候換,還有換過去為什麼回不來/images/emoticon/emoticon31.gif


上一篇
Day 9|Bitmap 與 HyperLogLog
下一篇
Day 11|底層編碼
系列文
從購物車到秒殺:30 天 Redis 高併發自學筆記 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言